package cn.itcast.common.config.aspect;


import cn.itcast.common.dto.ContextBean;
import cn.itcast.common.util.MDCUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * 会话上下文存取切面，主要用来缓存数据，一般用redis缓存
 */
@Aspect   //切面必须的注解
@Slf4j
@Component   //表示这是一个bean，被IOC控制翻转托管
@Order(0)  //指定执行顺序
public class ThreadContextBeanAspect {
    //过期时间10分钟
    private final int TIMEOUT=10*60;
    private final TimeUnit TIMEUNIT=TimeUnit.SECONDS;
    //request请求
    @Autowired
    private HttpServletRequest request;
//    //redis缓存
//    private RedisTemplate<String,Object> redis;


    /**
     * 切入点表达式,RequestMapping请求时触发
     */
    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")  //指定执行条件
    public void pointCut() {}

    /*前置通知*/
    @Before("pointCut()") //括号里面指定执行条件
    public void before() {
        //我们项目中使用的log4j2日志框架，在日志输出的时候，我们有个需求，需要将我们全局唯一的流程流水id打印到log4j的日志文件中
        //使用log4j2的MDC工具打日志，log4j2有高并发问题吗，同时几个请求会有干扰吗
        MDCUtil.removeFlowId();//每次请求都清空并创建新的flowid，用于新请求场景
        ContextBean.removeThreadContextBean();
        //创建缓存对象
        ContextBean c=null;
        String flowId=request.getParameter("flowId");//也可以用前端传的flowId，用于其他地方调接口场景，串联形成flowid链
        if(StringUtils.hasText(flowId)){
            //从redis获取缓存，判断是否为null，由于没有redis这里写死了数据，不判断
            c=new ContextBean();
            c.setFlowId(flowId);
        }

        if(c==null){
            c=ContextBean.build();
        }

        ContextBean.setThreadContextBean(c);
        //使用log4j2的MDC工具打日志
        MDCUtil.setFlowId(c.getFlowId());//放入flowid到日志文件，用于日志追踪，同一个请求使用同一个fowid，这样查flowid就可以查询整个请求的日志
        log.info("进入ThreadContextBeanAspect");
    }


    /**
     * 请求正常返回
     */
    @AfterReturning("pointCut()")  //returning指定返回值名称
    public void afterReturning() {
        // 处理完请求，返回内容
        ContextBean c=ContextBean.getThreadContextBean();
//        redis.set(c.getFlowId(),c,TIMEOUT,TIMEUNIT);
    }
}
